K8s 使用资源清单创建资源 (二)

标签选选择器是 K8s 中的一个重要的组成部分,用于不同的 Pod 控制器控制此类标签的 Pod,用于 Service 进行后端的关联等,所以对 Pod 标签的操作显得尤为的种要。同时在基本的 Pod 配置清单中, Containers 部分的配置包含了镜像的拉取规则,当 Docker 和 配置清单都配置有要执行的命令时,到底执行那一部分的命令?Pod 有生命周期,当然我们也可以在容器启动和销毁之前做一些操作。包括容器的重启策略等。从这些知识点中可以看,K8s 在保证已经存活,并且达到用户理想的状态其实做了很多的工作,在了解之后的原理之后就会觉得很有意思。

镜像拉取规则

Pod.spec.containers 字段中,spec.containers 类型为<[] object>,格式如下。

1
2
3
- name <String>
image <String>
imagePullPolicy <String>, 支持的值有 Always(总是拉取, 默认值),Never(从不拉取),IfNotPresent(如果存在则不拉取)。默认是 Always,但是如果镜像是 latest 版本,那么也是总是拉取的,除非手动指定 imagePullPolicy

命令优先级

在 Docker 中,命令的执行有 cmd 和 entrypoint。如果只有 cmd 那么就执行 cmd 的内容,如果同时存在 entrypoint 和 cmd,那么会将 cmd 的值作为参数传入 entrypoint 中执行。

而在 K8s 中,没有了 cmd 和 entrypoint,而是有 command 和 args。command 相当于 docker 中的 entrypoint,args 相当于 docker 中的 cmd。

那么什么时候使用容器的命令,什么时候使用 k8s 资源清单中的命令就显得及其的重要了,具体可以分为以下四种情况:

  1. 如果没有提供 command 和 args,那么就默认使用 docker 镜像中的 cmd 和 entrypoint。
  2. 如果提供了 command 但是没有 args,那么就只运行 command,镜像中的 entrypoint 和 cmd 都被忽略。
  3. 如果提供了 args 但是没有 command,那么就使用镜像中的 entrypoint,args 将作为 entrypoint 的参数,镜像中的 cmd 将被忽略。
  4. 如果 command 和 args 都提供了,那么镜像中的 entrypoint 和 args 都将被忽略。


更多信息,可见 https://k8smeetup.github.io/docs/tasks/inject-data-application/define-command-argument-container/

标签操作

一个资源应用可能有多个标签,而一个标签也可以分布在不同的资源上。标签的灵活使用可以将资源从不同角度进行分组,从而实现不同的管理。标签的名称和值的长度为最大36个字符。

查看 Pod 显示标签

1
kubectl get pods --show-labels
1
2
NAME                            READY   STATUS    RESTARTS   AGE    LABELS
nginx-deploy-5c9b546997-nv2xp 1/1 Running 0 4h7m pod-template-hash=5c9b546997,run=nginx-deploy

Pod 标签过滤

查看包含 app 的标签。显示结果新增一列,新增的一列为过滤的标签名称,下面显示过滤匹配的结果。-L 后面可跟多个标签,多个过滤的时候使用 “,” 进行分割。

1
kubectl get pods -L app
1
2
3
4
[root@iZrj94q5l72imm6kxm11qvZ rexyan]# kubectl get pods -L app
NAME READY STATUS RESTARTS AGE APP
nginx-deploy-5c9b546997-nv2xp 1/1 Running 0 4h10m
pod-demo 2/2 Running 0 15s myapp

表示只显示包含的 app 的标签,其余的不显示。后面也可跟多个标签,多个过滤的时候使用 “,” 进行分割。

1
kubectl get pods -l app

1
2
NAME       READY   STATUS    RESTARTS   AGE
pod-demo 2/2 Running 0 4m57s

Pod 新增标签

为 pod-demo 新增一个 release=canary 的标签。命令格式为 kubectl label + 资源类型 + 资源名称 + 标签值

1
kubectl label pods pod-demo release=canary
1
2
3
4
[root@iZrj94q5l72imm6kxm11qvZ rexyan]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deploy-5c9b546997-nv2 xp 1/1 Running 0 4h21m pod-template-hash=5c9b546997,run=nginx-deploy
pod-demo 2/2 Running 0 10m app=myapp,author=rexyan,release=canary

Pod修改标签

将上面的 release=canary 改为 release=stable,需要在刚才新增的命令上加上 –overwrite 选项。

1
kubectl label pods pod-demo release=stable --overwrite
1
2
3
4
[root@iZrj94q5l72imm6kxm11qvZ rexyan]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deploy-5c9b546997-nv2xp 1/1 Running 0 4h23m pod-template-hash=5c9b546997,run=nginx-deploy
pod-demo 2/2 Running 0 13m app=myapp,author=rexyan,release=stable

Node 查看标签

1
kubectl get node --show-labels
1
2
3
izrj94q5l72imm6kxm11qvz   Ready    master   4h57m   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qvz,kubernetes.io/os=linux,node-role.kubernetes.io/master=
izrj94q5l72imm6kxm11qwz Ready <none> 4h50m v1.14.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qwz,kubernetes.io/os=linux
izrj94q5l72imm6kxm11qxz Ready <none> 4h51m v1.14.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qxz,kubernetes.io/os=linux

Node 新增标签

1
kubectl label nodes izrj94q5l72imm6kxm11qxz type=test
1
2
3
4
5
kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
izrj94q5l72imm6kxm11qvz Ready master 5h10m v1.14.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qvz,kubernetes.io/os=linux,node-role.kubernetes.io/master=,type=master
izrj94q5l72imm6kxm11qwz Ready <none> 5h3m v1.14.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qwz,kubernetes.io/os=linux
izrj94q5l72imm6kxm11qxz Ready <none> 5h4m v1.14.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=izrj94q5l72imm6kxm11qxz,kubernetes.io/os=linux,type=test

指定 Pod 调度节点

nodelSelecter

Node 有标签,那我们就可以将一个 Pod 指定调度在哪一个节点上运行。在 Pod.spec 下有 nodelSelecter 字段,nodelSelecter 代表的意思是节点标签选择器。我们为之前的 pod-demo 设置 ports 和 nodeSelector,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: myapp
author: rexyan
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
- containerPort: 80
- name: busybox
image: busybox
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
nodeSelector:
type: test

示例会将 pod 调度到 type=test 的 节点上。

1
2
kubectl delete -f pod-demo.yaml 
kubectl create -f pod-demo.yaml
1
2
3
4
kubectl get pods -o wide 
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-5c9b546997-nv2xp 1/1 Running 0 5h7m 10.244.1.2 izrj94q5l72imm6kxm11qxz <none> <none>
pod-demo 2/2 Running 0 19s 10.244.1.3 izrj94q5l72imm6kxm11qxz <none> <none>

可以看到两个容器均调度到了 izrj945l72imm6kxm11qxz 的节点上,而这个节点就是被打上 type=test 标签的节点。

查看 pod 的详细信息中的 default-scheduler 字段也可以看到调度的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
kubectl describe pods pod-demo
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m35s default-scheduler Successfully assigned default/pod-demo to izrj94q5l72imm6kxm11qxz
Normal Pulling 3m35s kubelet, izrj94q5l72imm6kxm11qxz Pulling image "ikubernetes/myapp:v1"
Normal Pulled 3m32s kubelet, izrj94q5l72imm6kxm11qxz Successfully pulled image "ikubernetes/myapp:v1"
Normal Created 3m32s kubelet, izrj94q5l72imm6kxm11qxz Created container myapp
Normal Started 3m32s kubelet, izrj94q5l72imm6kxm11qxz Started container myapp
Normal Pulling 3m32s kubelet, izrj94q5l72imm6kxm11qxz Pulling image "busybox"
Normal Pulled 3m30s kubelet, izrj94q5l72imm6kxm11qxz Successfully pulled image "busybox"
Normal Created 3m30s kubelet, izrj94q5l72imm6kxm11qxz Created container busybox
Normal Started 3m30s kubelet, izrj94q5l72imm6kxm11qxz Started container busybox
nodeName

使用 nodeName,可以直接将一个 Pod 指定运行在某个 node 上,根据 node 名称。

许多资源支持内嵌的字段来定义其自己使用的标签选择器:

  1. matchLabels:表示直接给定键值就能进行选择
  2. matchExpressions:表示要基于给定的表达式来进行选择

标签选择器

等值关系

可以使用 = ,== 或者 !=

1
kubectl get pods -l author=rexyan

1
kubectl get pods -l author==rexyan,app=test  # author==rexyan且app=test
1
kubectl get pods -l author!=rexyan  # author不等于rexyan

集合关系

可以使用 KEY in (VALUE1, VALUE2) 或者 notin 或者 !KEY

1
kubectl get pods -l "author in (rexyan, yanrunsha, runsha.yan)"

1
kubectl get pods -l "author notin (rexyan, yanrunsha, runsha.yan)"

Pod 注解

annotations 是 Pod 的注解。与 lable 不同的地方在于,他不能用于挑选资源对象,仅用于为对象提供 “元数据”

修改 pod-demo.yaml, 内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: myapp
author: rexyan
annotations:
rexyan.me/create-by: "rexyan"
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
- name: busybox
image: busybox
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
nodeSelector:
type: test

将 pod 删除,并且重新创建

1
2
kubectl delete -f pod-demo.yaml 
kubectl create -f pod-demo.yaml

可以使用 describe 查看资源的注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
kubectl describe pods pod-demo
Name: pod-demo
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: izrj94q5l72imm6kxm11qxz/172.20.245.188
Start Time: Sat, 18 May 2019 22:27:11 +0800
Labels: app=myapp
author=rexyan
Annotations: rexyan.me/create-by: rexyan
Status: Running
IP: 10.244.1.4
Containers:
myapp:
Container ID: docker://0f3a448bb2c66d26c060ebf0fb65941265dc8b2cf9cb837fed88641e5478df0f
Image: ikubernetes/myapp:v1
Image ID: docker-pullable://docker.io/ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Sat, 18 May 2019 22:27:12 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-8dmfd (ro)
busybox:
Container ID: docker://89e2a12051d98435c427f091b4753a2900455641b397a5396f59b16426561c06
Image: busybox
Image ID: docker-pullable://docker.io/busybox@sha256:4b6ad3a68d34da29bf7c8ccb5d355ba8b4babcad1f99798204e7abb43e54ee3d
Port: <none>
Host Port: <none>
Command:
/bin/sh
-c
sleep 3600
State: Running
Started: Sat, 18 May 2019 22:27:13 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-8dmfd (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-8dmfd:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-8dmfd
Optional: false
QoS Class: BestEffort
Node-Selectors: type=test
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 18s default-scheduler Successfully assigned default/pod-demo to izrj94q5l72imm6kxm11qxz
Normal Pulled 17s kubelet, izrj94q5l72imm6kxm11qxz Container image "ikubernetes/myapp:v1" already present on machine
Normal Created 17s kubelet, izrj94q5l72imm6kxm11qxz Created container myapp
Normal Started 17s kubelet, izrj94q5l72imm6kxm11qxz Started container myapp
Normal Pulling 17s kubelet, izrj94q5l72imm6kxm11qxz Pulling image "busybox"
Normal Pulled 16s kubelet, izrj94q5l72imm6kxm11qxz Successfully pulled image "busybox"
Normal Created 16s kubelet, izrj94q5l72imm6kxm11qxz Created container busybox
Normal Started 16s kubelet, izrj94q5l72imm6kxm11qxz Started container busybox

Pod 的生命周期

状态:Pending,Running,Failed,Succeeded,Unknow……

Pod 生命周期中的重要行为:

1
2
3
4
初始化容器
容器探测:
liveness(用来判定容器是否正常)
readiness(用来判定容器中的服务是否正常)

容器重启策略

restartPolicy 用于定义容器的充气策略。支持以下几种。

Always(默认),OnFailure(失败后才重启),Never(从不重启)

进入容器和日志查看

查看容器日志和进入容器分别使用kubectl logskubectl exec 命令。当 Pod 中只有一个容器的时候,我们可以不使用 -c 参数指定进入哪一个容器,但是如果 Pod 中有多个容器的时候,就需要使用-c 来指定具体的容器。